package com.sojson.serversocket.config.handler;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.springframework.stereotype.Component;

import com.sojson.serversocket.util.ServerSocketPoolUtil;
import com.sojson.serversocket.util.ServerSocketUtil;
import com.sojson.serversocket.util.bean.ServerSocketConnect;
import com.sojson.serversocket.util.enums.EElectricType;
import com.sojson.serversocket.util.enums.EServerSocketFuncType;
import com.sojson.util.DateUtil;
import com.sojson.util.HexUtil;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;

/**
 * ServerSocket心跳包处理器
 *
 * @author liu
 * @date 2024-05-30
 */
@Slf4j
@Component
public class ServerSocketHandlerHeartbeat {

    private Map<String, Long> times = new HashMap<>();

    public void run(ChannelHandlerContext ctx, String data, String addr, String addrRever) throws Exception {
        // 帧长度
        int len = data.length() / 2;
        // 校验码
        String verifyCode = data.substring((len - 3) * 2, (len - 1) * 2);

        HexUtil.crcVerify(data, verifyCode, ServerSocketUtil.HEAD_HEARTBEAT, (len - 3) * 2);

        Byte[] barr = null;

        // 判断是否需要注册
        ServerSocketConnect connect = ServerSocketPoolUtil.get(addrRever);
        if (connect == null) {
            ServerSocketPoolUtil.put(EElectricType.FOUR, addrRever, ctx);
            try {
                // 总用电量
                String totalWattage = data.substring(94, 102);
                // 电表状态字
                String meterStatusWord = Integer.toBinaryString(HexUtil.parseHexOne(data.substring(162, 164)));
                StringBuilder str = new StringBuilder();
                int length = 8 - meterStatusWord.length();
                for (int i = 0; i < length; i++) {
                    str.append(ServerSocketUtil.COMP_ZORE);
                }
                meterStatusWord = str.append(meterStatusWord).substring(4, 5);

            } catch (Exception e) {
                ServerSocketPoolUtil.removeConnect(addrRever);
                log.error(e.getMessage(), e);
                return;
            }
        } else if (connect.getCtx() == null) {
            ServerSocketPoolUtil.put(EElectricType.FOUR, addrRever, ctx);
        }

        int hour = LocalTime.now().getHour();
        Long dateLast = times.get(addrRever);
        long currentTimeMillis = System.currentTimeMillis();
        if ((dateLast == null || currentTimeMillis - dateLast > 2 * 60 * 60 * 1000)) {
            // 总用电量
            String totalWattage = data.substring(94, 102);
            // 电表状态字
            String meterStatusWord = Integer.toBinaryString(HexUtil.parseHexOne(data.substring(162, 164)));
            StringBuilder str = new StringBuilder();
            int length = 8 - meterStatusWord.length();
            for (int i = 0; i < length; i++) {
                str.append(ServerSocketUtil.COMP_ZORE);
            }
            meterStatusWord = str.append(meterStatusWord).substring(4, 5);

            times.put(addrRever, currentTimeMillis);
        }

        // 回复
        revert(ctx, data, addr, addrRever);
    }

    /**
     * 心跳回复
     *
     * @param ctx
     * @param data
     * @param addr
     * @param addrRever
     * @throws Exception
     */
    public void revert(ChannelHandlerContext ctx, String data, String addr, String addrRever) throws Exception {
        // 电表模式
        String funcCode = data.substring(10, 12);

        // 回复帧
        StringBuilder result = new StringBuilder(ServerSocketUtil.HEAD_HEARTBEAT_RESULT);
        result.append(addr);
        if (EServerSocketFuncType.MULTI_RATE.getCode().equals(funcCode)) {
            Date date = new Date();
            Instant instant = date.toInstant();
            ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault());
            LocalDateTime localDateTime = zdt.toLocalDateTime();
            String yyMMddHHmmss = DateUtil.YYYYMMDDHHMMSS.format(localDateTime);
            int week = localDateTime.getDayOfWeek().getValue();
            result.append(yyMMddHHmmss + ServerSocketUtil.COMP_ZORE + (week == 7 ? 0 : week));
        }
        result.append(ServerSocketUtil.END);
        log.info("ServerSocket心跳回复: " + result);
        ByteBuf byteBuf = Unpooled.copiedBuffer(HexUtil.parseHex(result.toString()));
        ChannelFuture writeAndFlush = ctx.channel().writeAndFlush(byteBuf);

        // 添加到连接池
        writeAndFlush.sync();
    }

}